<!DOCTYPE html>
<html lang="zh-CN">
<head hexo-theme='https://github.com/volantis-x/hexo-theme-volantis/tree/4.1.5'>
  <meta charset="utf-8">
  <!-- SEO相关 -->
  
    
  
  <!-- 渲染优化 -->
  <meta http-equiv='x-dns-prefetch-control' content='on' />
  <link rel='dns-prefetch' href='https://cdn.jsdelivr.net'>
  <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin>
  <meta name="renderer" content="webkit">
  <meta name="force-rendering" content="webkit">
  <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
  <meta name="HandheldFriendly" content="True" >
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

  <!-- 页面元数据 -->
  
  <title>TypeScript学习总结（一） - Alan|前端博客</title>
  
    <meta name="keywords" content="TypeScript">
  

  
    <meta name="description" content="TypeScript常用知识点总结">
  

  <!-- feed -->
  

  <!-- import meta -->
  

  <!-- link -->
  
    <link rel="shortcut icon" type='image/x-icon' href="https://gitee.com/alannum3/MyImages/raw/master/img/basketball-ball.png">
  

  <!-- import link -->
  

  
    
<link rel="stylesheet" href="/css/first.css">

  

  
  <link rel="stylesheet" href="/css/style.css" media="print" onload="this.media='all';this.onload=null">
  <noscript><link rel="stylesheet" href="/css/style.css"></noscript>
  

  <script id="loadcss"></script>

</head>

<body>
  

<header id="l_header" class="l_header auto shadow blur " style='opacity: 0' >
  <div class='container'>
  <div id='wrapper'>
    <div class='nav-sub'>
      <p class="title"></p>
      <ul class='switcher nav-list-h m-phone' id="pjax-header-nav-list">
        <li><a id="s-comment" class="fas fa-comments fa-fw" target="_self" href='javascript:void(0)'></a></li>
        
          <li><a id="s-toc" class="s-toc fas fa-list fa-fw" target="_self" href='javascript:void(0)'></a></li>
        
      </ul>
    </div>
		<div class="nav-main">
      
        
        <a class="title flat-box" target="_self" href='/'>
          
          
            <i class='fas fa-basketball-ball'></i>
          
          
            Alan
          
        </a>
      

			<div class='menu navigation'>
				<ul class='nav-list-h m-pc'>
          
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/
                  
                  
                  
                    id="categories"
                  >
                  <i class='fas fa-folder-open fa-fw'></i>分类
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/archives/
                  
                  
                  
                    id="archives"
                  >
                  <i class='fas fa-archive fa-fw'></i>归档
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/friends/
                  
                  
                  
                    id="friends"
                  >
                  <i class='fas fa-link fa-fw'></i>友链
                </a>
                
              </li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box header toggle-mode-btn">
                  <i class='fas fa-moon fa-fw'></i>dark
                </a>
              <li>
            
          
          
            
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" 
                  
                  
                  >
                  <i class='fas fa-ellipsis-v fa-fw'></i>更多
                </a>
                
                  <ul class="list-v">
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=https://alanwang.avosapps.us/
                  
                  
                    target="_blank"
                  
                  
                    id="https:alanwangavosappsus"
                  >
                  <i class='fas fa-comments fa-fw'></i>评论管理
                </a>
                
              </li>
            
          
                    
                  </ul>
                
              </li>
            
          
          
				</ul>
			</div>

      <div class="m_search">
        <form name="searchform" class="form u-search-form">
          <i class="icon fas fa-search fa-fw"></i>
          <input type="text" class="input u-search-input" placeholder="Search..." />
        </form>
      </div>

			<ul class='switcher nav-list-h m-phone'>
				
					<li><a class="s-search fas fa-search fa-fw" target="_self" href='javascript:void(0)'></a></li>
				
				<li>
          <a class="s-menu fas fa-bars fa-fw" target="_self" href='javascript:void(0)'></a>
          <ul class="menu-phone list-v navigation white-box">
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/categories/
                  
                  
                  
                    id="categories"
                  >
                  <i class='fas fa-folder-open fa-fw'></i>分类
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/archives/
                  
                  
                  
                    id="archives"
                  >
                  <i class='fas fa-archive fa-fw'></i>归档
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=/friends/
                  
                  
                  
                    id="friends"
                  >
                  <i class='fas fa-link fa-fw'></i>友链
                </a>
                
              </li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box header toggle-mode-btn">
                  <i class='fas fa-moon fa-fw'></i>dark
                </a>
              <li>
            
          
            
              
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" 
                  
                  
                  >
                  <i class='fas fa-ellipsis-v fa-fw'></i>更多
                </a>
                
                  <ul class="list-v">
                    
                      
            
              <li>
                <a class="menuitem flat-box faa-parent animated-hover" href=https://alanwang.avosapps.us/
                  
                  
                    target="_blank"
                  
                  
                    id="https:alanwangavosappsus"
                  >
                  <i class='fas fa-comments fa-fw'></i>评论管理
                </a>
                
              </li>
            
          
                    
                  </ul>
                
              </li>
            
          
            
          </ul>
        </li>
			</ul>
		</div>
	</div>
  </div>
</header>

  <div id="l_body">
    <div id="l_cover">
  
    
        <div id="half" class='cover-wrapper post focus' style="display: ;">
          
            <div id='cover-backstretch'></div>
          
          <div class='cover-body'>
  <div class='top'>
    
    
      <p class="title">Alan</p>
    
    
      <p class="subtitle">此刻想举重若轻，之前必要负重前行</p>
    
  </div>
  <div class='bottom'>
    <div class='menu navigation'>
      <div class='list-h'>
        
          
            <a href="https://alannum3.gitee.io/"
              
              
              id="https:alannum3giteeio">
              <img src='https://cdn.jsdelivr.net/gh/twitter/twemoji@13.0/assets/svg/1f389.svg'><p>Next.js博客</p>
            </a>
          
        
      </div>
    </div>
  </div>
</div>

          <div id="scroll-down" style="display: none;"><i class="fa fa-chevron-down scroll-down-effects"></i></div>
        </div>
    
  
  </div>

    <div id='safearea'>
      <div class='body-wrapper' id="pjax-container">
        

<div class='l_main'>
  <article class="article post white-box reveal md shadow article-type-post" id="post" itemscope itemprop="blogPost">
  


  
  <div class="article-meta" id="top">
    
    
    
      <h1 class="title">
        TypeScript学习总结（一）
      </h1>
      <div class='new-meta-box'>
        
          
            
  <div class='new-meta-item category'>
    <a class='notlink'>
      <i class="fas fa-folder-open fa-fw" aria-hidden="true"></i>
      <a class="category-link" href="/categories/%E5%89%8D%E7%AB%AF/">前端</a><span class="sep"></span><a class="category-link" href="/categories/%E5%89%8D%E7%AB%AF/TypeScript/">TypeScript</a>
    </a>
  </div>


          
        
          
            <div class="new-meta-item date" itemprop="dateUpdated" datetime="2020-07-01T11:52:09+08:00">
  <a class='notlink'>
    <i class="fas fa-edit fa-fw" aria-hidden="true"></i>
    <p>更新于：2020年7月1日 11:52</p>
  </a>
</div>

          
        
          
            
  <div class="new-meta-item wordcount">
    <a class='notlink'>
      <i class="fas fa-keyboard fa-fw" aria-hidden="true"></i>
      <p>字数：2.8k字</p>
    </a>
  </div>
  <div class="new-meta-item readtime">
    <a class='notlink'>
      <i class="fas fa-hourglass-half fa-fw" aria-hidden="true"></i>
      <p>时长：12分钟</p>
    </a>
  </div>


          
        
          
            
  <div class="new-meta-item browse leancloud">
    <a class='notlink'>
      
      <div id="lc-pv" data-title="TypeScript学习总结（一）" data-path="/posts/fc7889ef/">
        <i class="fas fa-fire fa-fw" aria-hidden="true"></i>
        <span id='number'><i class="fas fa-circle-notch fa-spin fa-fw" aria-hidden="true"></i></span>
        次浏览
      </div>
    </a>
  </div>


          
        
      </div>
    
  </div>


  
  <p>TypeScript常用知识点总结</p>
<a id="more"></a>

<h3 id="什么是TypeScript"><a href="#什么是TypeScript" class="headerlink" title="什么是TypeScript"></a>什么是TypeScript</h3><p>TypeScript是JavaScript的一个超集，在JavaScript的基础上增加了可选的<strong>静态类型</strong>和基于类的面向对象编程。它可以编译成纯JavaScript，未编译的ts代码无法在浏览器执行。我们可以把它和JavaScript的关系理解成css和less、sass的关系。</p>
<h3 id="TypeScript好在哪里"><a href="#TypeScript好在哪里" class="headerlink" title="TypeScript好在哪里"></a>TypeScript好在哪里</h3><ul>
<li>TS可以进行动态类型检测，可以检测出一些潜在的bug（例如拼写错误、参数缺失、undefined等），提升代码健壮性</li>
<li>使用vscode进行开发可以很好的提示代码，提高开发效率</li>
<li>代码可读性好</li>
</ul>
<h3 id="创建第一个TypeScript文件"><a href="#创建第一个TypeScript文件" class="headerlink" title="创建第一个TypeScript文件"></a>创建第一个TypeScript文件</h3><p>首先安装TypeScript</p>
<pre><code>npm install -g typescript</code></pre><p>安装后看是否成功</p>
<pre><code>tsc --version</code></pre><p>我安装后出现了以下问题：<br><img src="" data-original="https://gitee.com/alannum3/MyImages/raw/master/img/image-20200614175730166.png" alt="image-20200614175730166"><br>这种情况只需要以管理员的身份打开命令行运行以下命令：</p>
<pre><code>set-ExecutionPolicy RemoteSigned</code></pre><p>创建第一个ts文件<code>Hello.ts</code></p>
<pre><code class="tsx">function sayHello(name:String) {
  console.log(`Hello ${name}`);
}
let person = &quot;Alan&quot;;
sayHello(person);</code></pre>
<p>我们发现ts代码和普通的js代码在<code>sayHello</code>函数的参数上有所不同。<br><code>sayHello(name: String)</code><br>大致的意思就是<code>sayHello</code>传入一个名为name的参数，该参数的类型必须是<code>String</code>，不然无法通过ts的编译。<br>代码写好后用tsc编译上面的<code>Hello.ts</code>文件</p>
<pre><code>tsc Hello.ts</code></pre><p>编译成功后在同级目录下生成一个<code>Hello.js</code>文件，可以看到生成的js文件只是将es6语法转化成了es5语法，并没有改变其他代码。</p>
<pre><code class="js">function sayHello(name) {
    console.log(&quot;Hello &quot; + name);
}
var person = &quot;Alan&quot;;
sayHello(person);</code></pre>
<p>如果把<code>Hello.ts</code>文件改写一下</p>
<pre><code class="tsx">function sayHello(name:String) {
  const text = 3 + name;
  console.log(`Hello ${name}`);
}
let person = 123;
sayHello(person);</code></pre>
<p>再次编译发现会报错但是仍然能生成js文件：<br><img src="" data-original="https://gitee.com/alannum3/MyImages/raw/master/img/image-20200614180440953.png" alt="image-20200614180440953"></p>
<p>上面错误的具体意思是</p>
<ul>
<li>由于声明了函数形参<code>name</code>为静态类型<code>string</code>，而在调用时传入得是number类型<code>123</code>，与前面的string不符。</li>
<li>在<code>sayHello</code>函数中将<code>name(string)</code>和<code>3(number)</code>两种不同类型得值进行了相加。</li>
</ul>
<p>我们发现每次都要通过tsc来编译ts文件能得到js文件后再去运行js文件，过于麻烦。可以使用插件<code>ts-node</code>来直接运行ts文件。</p>
<pre><code>npm i ts-node -g</code></pre><pre><code>ts-node Hello.ts</code></pre><blockquote>
<p>ts能够尝试分析变量类型（类型推断），ts无法分析出的变量最好显式声明变量类型（类型注解）</p>
</blockquote>
<h3 id="基础类型"><a href="#基础类型" class="headerlink" title="基础类型"></a>基础类型</h3><p>变量的声明：<code>let [变量名] : [类型] = 值</code></p>
<p>例如： <code>let age: number =  21</code></p>
<p>TypeScript支持与JavaScript几乎相同的数据类型</p>
<ul>
<li>boolean(布尔值)</li>
<li>number(数值)</li>
<li>string(字符串)</li>
<li>[]/Array&lt;元素类型&gt;(数组)</li>
<li>元组Tuple</li>
<li>enum(枚举)</li>
<li>any(任何值)</li>
<li>void(空值)</li>
<li>null</li>
<li>undefined</li>
<li>never</li>
</ul>
<h3 id="数组"><a href="#数组" class="headerlink" title="数组"></a>数组</h3><p>有2种方式定义数组</p>
<pre><code class="tsx">let arr : number[] = [1,2,3] // 元素类型后接上`[]`
let arr : Array&lt;number&gt; = [1,2,3] // 数组泛型
let arr: (number | string)[] = [1, &#39;2&#39;, &#39;4&#39;] // 元素类型可以是number或string（类似元组）</code></pre>
<h3 id="元组tuple"><a href="#元组tuple" class="headerlink" title="元组tuple"></a>元组tuple</h3><p>表示一个数组（各个元素的类型不必相同）</p>
<pre><code class="tsx">let list : [string, number]; //第一个元素为string类型，第二个为number类型
a = [&#39;abc&#39;, 123] //合格
b = [123, &#39;abc&#39;] //不合格</code></pre>
<h3 id="枚举"><a href="#枚举" class="headerlink" title="枚举"></a>枚举</h3><p>其实有点类似对象<br>看例子吧</p>
<pre><code class="tsx">enum lan {js, ts, css};
console.log(lan.js); // 0   js对应的下标，第一个默认下标为0

enum lan {
  js = 3,
  ts,
  css,
}
console.log(lan.js); // 3
console.log(lan.ts); // 4
console.log(lan.css); // 5

enum lan {
  js,
  ts = 3,
  css,
}
console.log(lan.js); // 0
console.log(lan.ts); // 3
console.log(lan.css); // 4
console.log(lan[4]); // css
console.log(lan[1]); // undefined
// 第一个默认下标为0，css接着ts的值+1

enum lan {js = &#39;good&#39;, ts = &#39;nice&#39;, css = &#39;well&#39;};
console.log(lan.js); // good</code></pre>
<h3 id="any"><a href="#any" class="headerlink" title="any"></a>any</h3><p>顾名思义，任意值，当我们想为还不清楚类型的变量指定一个类型时，<code>any</code>就是最好的选择🤭</p>
<pre><code class="tsx">let a:any =4;
a = &#39;123&#39;; //合格


let arr : any[] = [1, &#39;123&#39;, true]; // 和元组很像
arr[1] = &#39;good&#39;;</code></pre>
<h3 id="void"><a href="#void" class="headerlink" title="void"></a>void</h3><p>常用于无返回值的函数声明</p>
<pre><code class="tsx">function func() : void {
  console.log(&#39;learning typescript...&#39;);
}
func(); //合格


function func() : void {
  return 1;
}
func(); // 不合格：Type &#39;1&#39; is not assignable to type &#39;void&#39;</code></pre>
<h3 id="null和undefined"><a href="#null和undefined" class="headerlink" title="null和undefined"></a>null和undefined</h3><p>用处不大，默认情况下是所有类型的子类型，例如下面代码是没有问题的：</p>
<pre><code class="tsx">let a:string;
a = undefined;
a = null;</code></pre>
<p><strong>但是</strong>，当指定<code>--strictNullChecks</code>标记时，null和undefined只能赋值给void和他们自己本身。</p>
<h3 id="never"><a href="#never" class="headerlink" title="never"></a>never</h3><p>表示永不存在的值的类型<br>never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型；<br>变量也可能是never类型，当它们被永不为真的类型保护所约束时。</p>
<p>never类型是任何类型的子类型，也可以赋值给任何类型；然而，没有类型是never的子类型或可以赋值给never类型（除了never本身之外）。 即使any也不可以赋值给never。</p>
<pre><code class="tsx">function error(message:string) : never{
  throw new Error(message);
}

// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
  while (true) {
  }
}</code></pre>
<h3 id="结构赋值的写法"><a href="#结构赋值的写法" class="headerlink" title="结构赋值的写法"></a>结构赋值的写法</h3><pre><code class="tsx">function sayAge({name, age}: {name: string | number, age: number}): void {
  console.log(`${name} is ${age} years old`);
}
sayAge({name: &#39;Alan&#39;, age: 22})
sayAge({name: 2, age: 22})</code></pre>
<h3 id="联合类型"><a href="#联合类型" class="headerlink" title="联合类型"></a>联合类型</h3><p>用<code>|</code>来表示取值存在多种可能</p>
<pre><code class="tsx">let a: string | number;
a = 1;
a = &#39;A&#39;;</code></pre>
<h3 id="类型断言"><a href="#类型断言" class="headerlink" title="类型断言"></a>类型断言</h3><p>可以自己指定一个值的类型<br>格式如下<br><code>&lt;类型&gt;值</code><br><code>值 as 类型</code></p>
<pre><code class="tsx">interface student {
  isStudent: boolean;
  education: number;
}
interface worker {
  isStudent: boolean;
  seniority: number;
}
function Recruit(candidate: worker | student): void {
  if (candidate.isStudent) {
    console.log(`your education is ${(candidate as student).education}`);
  } else {
    console.log(`your seniority is ${(candidate as worker).seniority}`);
  }
}

const a: student = { isStudent: true, education: 4 };
const b: worker = { isStudent: false, seniority: 2 };
Recruit(a);
Recruit(b);
</code></pre>
<p>由于<code>candidate</code>使用了联合类型，所以ts无法判断<code>candidate</code>究竟是属于<code>student</code>还是<code>worker</code>，所以要使用类型断言来显式告诉ts。</p>
<p>当然还有其他方式来实现</p>
<pre><code class="tsx">interface student {
  isStudent: boolean;
  education: number;
}
interface worker {
  isStudent: boolean;
  seniority: number;
}
function Recruit(candidate: worker | student): void {
  &#39;education&#39; in candidate &amp;&amp;
    console.log(`your education is ${candidate.education}`);
  &#39;seniority&#39; in candidate &amp;&amp;
    console.log(`your seniority is ${candidate.seniority}`);
}

const a: student = { isStudent: true, education: 4 };
const b: worker = { isStudent: false, seniority: 2 };
Recruit(a);
Recruit(b);</code></pre>
<ul>
<li>typeof</li>
<li>instanceof</li>
</ul>
<h3 id="接口interface"><a href="#接口interface" class="headerlink" title="接口interface"></a>接口interface</h3><p>先看一个接口的例子</p>
<pre><code class="tsx">interface person {
  name: string;
}
function work(personObj:person) {
  console.log(personObj.name);
}
let person1 = {name: &#39;Alan&#39;, age: 21};
work(person1);
let person2 = {age: 21};
work(person2);</code></pre>
<p><img src="" data-original="https://gitee.com/alannum3/MyImages/raw/master/img/image-20200615180720618.png" alt="image-20200615180720618"></p>
<p>定义接口的关键字是<code>interface</code><br>这个例子需要传入work的参数必须是一个带有name(string)的对象，可以理解为我要招聘一个有名字的员工，没有名字的都不需要。当然我们的person1中还多了一个<code>age</code>属性，这并不会报错。可是当我们直接传递参数时是会出错的。</p>
<pre><code class="js">work({name: &#39;Alan&#39;, age: 21});</code></pre>
<p>那如果我不确定要招聘的员工除了有姓名外还需要其他什么属性时，可以像下面一样重新定义接口就可以解决上面的问题了。</p>
<pre><code class="tsx">interface person {
  name: string;
  [propName: string]: any
}</code></pre>
<h4 id="可选属性"><a href="#可选属性" class="headerlink" title="可选属性"></a>可选属性</h4><p>那如果我的招聘条件是最好懂typescript的，这个时候typescript就是可有可无的（最好懂，嘿嘿😜），那我们就要用到<strong>可选属性</strong>了<br><code>可选属性</code>在可选属性名后面加上一个<code>?</code></p>
<pre><code class="tsx">interface person {
  name: string;
  ts?: boolean;
}
function Recruit(personObj:person) : string{
  if(personObj.ts) {
    return `congratulations!${personObj.name}`;
  } else {
    return `sorry,${personObj.name}, we need a employee who know ts!`;
  }
}
let person1 = {name: &#39;Alan&#39;, age: 21, ts: true};
console.log(Recruit(person1));
let person2 = {name: &#39;Bob&#39;, age: 21};
console.log(Recruit(person2));
</code></pre>
<h4 id="只读属性"><a href="#只读属性" class="headerlink" title="只读属性"></a>只读属性</h4><p>我们都知道人的名字都是不可以改变的（一般情况下），这个时候我们对person接口里面的name属性稍作修改，在属性名name前加上<code>readonly</code>。</p>
<div class="note info"><p>当然也可以使用setter/getter来实现</p></div>

<pre><code class="tsx">interface person {
  readonly name: string;
  ts?: boolean;
}
let person1: person = {name: &#39;Alan&#39;};
person1.name = &#39;Bob&#39;; // Cannot assign to &#39;name&#39; because it is a read-only property.</code></pre>
<p><strong>我们发现readonly和const的作用好像有点相似，那我们什么时候使用readonly什么时候使用const呢？</strong><br>变量—-&gt;const<br>属性—-&gt;readonly</p>
<h4 id="函数类型的接口"><a href="#函数类型的接口" class="headerlink" title="函数类型的接口"></a>函数类型的接口</h4><p>接口除了可以描述带有属性的对象外，还可以描述函数类型<br>这里创建一个函数来检查你有没有打卡😁</p>
<pre><code class="tsx">interface attendanceFunc {
  (name:string, startTime: number, endTime: number) : boolean;
}
let checkAttendance : attendanceFunc;
checkAttendance = function (name:string, startTime: number, endTime: number) : boolean {
  let result = startTime &lt; 9 &amp;&amp; endTime &gt;18;
  return result;
}
console.log(checkAttendance(&#39;Alan&#39;, 10, 19)); // false</code></pre>
<p>看一下接口的声明：</p>
<pre><code class="tsx">interface attendanceFunc {
  (name:string, startTime: number, endTime: number) : boolean;
}</code></pre>
<p><code>name,startTime,endTime</code>放在<code>()</code>中代表函数的参数<br><code>:boolean</code>表示函数的返回值类型<br>当然上面例子中的<code>checkAttendance</code>的形参以及函数的返回值来说可以不指定类型，因为<code>checkAttendance</code>复制给了<code>attendanceFunc</code>变量，类型检查器会自动(按照接口中参数的顺序)推断出参数以及返回值的类型，也就是说写成下面这样也是可以的。<strong>函数中的参数名可以不和接口中的相同</strong></p>
<pre><code class="tsx">interface attendanceFunc {
  (name:string, startTime: number, endTime: number) : boolean;
}
let checkAttendance : attendanceFunc;
checkAttendance = function (n, startTime, endTime) {
  let result = startTime &lt; 9 &amp;&amp; endTime &gt;18;
  return result;
}
console.log(checkAttendance(&#39;Alan&#39;, 10, 19)); // false</code></pre>
<h4 id="接口的继承"><a href="#接口的继承" class="headerlink" title="接口的继承"></a>接口的继承</h4><p>一个接口可以继承1个或者多个接口：<br>继承使用关键词<code>extends</code></p>
<pre><code class="tsx">interface person {
  name : string;
}
interface student {
  studentId : number;
}
interface seniorStudent extends person, student {
  grade: string;
}
let student1 : seniorStudent = {name: &#39;Alan&#39;, studentId: 1, grade: &#39;one&#39;};
console.log(student1);</code></pre>
<h3 id="类class"><a href="#类class" class="headerlink" title="类class"></a>类class</h3><p>TS中的类和ES6中的类很相似，这里只介绍不同的地方</p>
<h4 id="变量修饰符"><a href="#变量修饰符" class="headerlink" title="变量修饰符"></a>变量修饰符</h4><ul>
<li>public（默认）</li>
<li>private（私有，不能在声明它的类的外部访问）</li>
<li>protected（和private类似，不同的是protected声明的变量可以在派生类（即子类）中访问）</li>
</ul>
<h4 id="静态属性static"><a href="#静态属性static" class="headerlink" title="静态属性static"></a>静态属性static</h4><pre><code class="tsx">class Person {
  static fingerNum = 5;
}

// 只能通过类来访问
console.log(Person.fingerNum);
// 不能通过实例访问
console.log(new Person().fingerNum);</code></pre>
<pre><code class="tsx">// 单例模式创建唯一的实例
class singleClass {
  private static instance: singleClass;
  private constructor(public name: string) {}

  static getInstance() {
    if (!this.instance) {
      this.instance = new singleClass(&#39;Alan&#39;);
    }
    return this.instance;
  }
}

const class1 = singleClass.getInstance();
const class2 = singleClass.getInstance();
console.log(class1.name); // Alan
console.log(class1 === class2); // true</code></pre>
<h4 id="构造函数"><a href="#构造函数" class="headerlink" title="构造函数"></a>构造函数</h4><pre><code class="tsx">class Person {
  constructor(name, mobile, sex) {
    this.name = name;
    this.mobile = mobile;
    this.sex = sex;
  }
  public name: string;
  private mobile: string;
  protected sex: string;
}</code></pre>
<p>上面的代码可以简写成下面这样</p>
<pre><code class="tsx">class Person {
  constructor(name: string, private mobile: string, protected sex: string) {
  }
}</code></pre>
<h4 id="抽象类"><a href="#抽象类" class="headerlink" title="抽象类"></a>抽象类</h4><ul>
<li>不能被实例化</li>
<li>要使用的话要声明其派生类，并且重写其中的抽象方法</li>
</ul>
<pre><code class="tsx">abstract class Animal {
  constructor(public name: string) {}
  sayHello() {
    console.log(&#39;hello&#39;);
  }
  // 声明抽象方法
  abstract action(): void;
}

class Bird extends Animal{
  constructor(name) {
    super(name);
  }
  action() {
    console.log(&#39;jijiji&#39;);
  }
}

const bird = new Bird(&#39;qc&#39;);
console.log(bird);
// Bird { name: &#39;qc&#39; }</code></pre>
<h3 id="泛型"><a href="#泛型" class="headerlink" title="泛型"></a>泛型</h3><blockquote>
<p>泛型（Generics）是指在定义函数、接口或类的时候，<strong>不预先指定</strong>具体的类型，而在<strong>使用的时候</strong>再指定类型的一种特性。</p>
</blockquote>
<p>用法：&lt;泛型名&gt;</p>
<pre><code class="tsx">function Recruit&lt;T&gt;(name: string, props: T) {
  return name + props;
}
// 显式指定为T为number类型
console.log(Recruit&lt;number&gt;(&#39;Alan&#39;, 123)); // Alan123
// TS自动推断为number类型，和上面效果一样
console.log(Recruit(&#39;Alan&#39;, 123)); // Alan123
console.log(Recruit(&#39;Alan&#39;, [1, 2, 3])); // Alan1,2,3</code></pre>
<h4 id="泛型约束"><a href="#泛型约束" class="headerlink" title="泛型约束"></a>泛型约束</h4><p>试用extends约束泛型</p>
<pre><code class="tsx">interface info {
  mobile: string;
}

// T泛型必须满足info
function Recruit&lt;T extends info&gt;(name: string, props: T) {
  return name + props.mobile;
}

console.log(Recruit(&#39;Alan&#39;, { mobile: &#39;1232910830&#39; })); // Alan1232910830</code></pre>

  
  
    
    <div class='footer'>
      
        <div class='references'>
          <section class='header'>
            
              <i class="fas fa-quote-left fa-fw" aria-hidden="true"></i>
            
            <span>参考资料</span>
          </section>
          <section class='body'>
            <ul>
              
                <li>
                  <a href="https://typescript.bootcss.com/basic-types.html" rel="external nofollow noopener noreferrer" target="_blank">
                  https://typescript.bootcss.com/basic-types.html
                  </a>
                </li>
              
                <li>
                  <a href="https://coding.imooc.com/class/412.html" rel="external nofollow noopener noreferrer" target="_blank">
                  https://coding.imooc.com/class/412.html
                  </a>
                </li>
              
            </ul>
          </section>
        </div>
      
      
      
        <div class='copyright'>
          <blockquote>
            
              
                <p>博客内容遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议</p>

              
            
              
                <p>本文永久链接是：<a href=https://alanwang.site/posts/fc7889ef/>https://alanwang.site/posts/fc7889ef/</a></p>
              
            
          </blockquote>
        </div>
      
      
    </div>
  
  
    


  <div class='article-meta' id="bottom">
    <div class='new-meta-box'>
      
        
          <div class="new-meta-item date" itemprop="dateUpdated" datetime="2020-07-01T11:52:09+08:00">
  <a class='notlink'>
    <i class="fas fa-edit fa-fw" aria-hidden="true"></i>
    <p>更新于：2020年7月1日 11:52</p>
  </a>
</div>

        
      
        
          
  
  <div class="new-meta-item meta-tags"><a class="tag" href="/tags/TypeScript/" rel="nofollow"><i class="fas fa-tags fa-fw" aria-hidden="true"></i><p>TypeScript</p></a></div>


        
      
        
          
  <div class="new-meta-item share -mob-share-list">
  <div class="-mob-share-list share-body">
    
      
        <a class="-mob-share-qq" title="" rel="external nofollow noopener noreferrer"
          
          href="http://connect.qq.com/widget/shareqq/index.html?url=https://alanwang.site/posts/fc7889ef/&title=TypeScript学习总结（一） - Alan|前端博客&summary=TypeScript常用知识点总结"
          
          >
          
            <img src="" data-original="https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/logo/128/qq.png">
          
        </a>
      
    
      
        <a class="-mob-share-qzone" title="" rel="external nofollow noopener noreferrer"
          
          href="https://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=https://alanwang.site/posts/fc7889ef/&title=TypeScript学习总结（一） - Alan|前端博客&summary=TypeScript常用知识点总结"
          
          >
          
            <img src="" data-original="https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/logo/128/qzone.png">
          
        </a>
      
    
      
        <a class="-mob-share-weibo" title="" rel="external nofollow noopener noreferrer"
          
          href="http://service.weibo.com/share/share.php?url=https://alanwang.site/posts/fc7889ef/&title=TypeScript学习总结（一） - Alan|前端博客&summary=TypeScript常用知识点总结"
          
          >
          
            <img src="" data-original="https://cdn.jsdelivr.net/gh/volantis-x/cdn-org/logo/128/weibo.png">
          
        </a>
      
    
      
    
      
    
  </div>
</div>



        
      
    </div>
  </div>


  
  

  
    <div class="prev-next">
      
        <a class='prev' href='/posts/c05e5480/'>
          <p class='title'><i class="fas fa-chevron-left" aria-hidden="true"></i>React入门学习总结</p>
          <p class='content'>总结学习React以及相关插件时遇到的难点以及重点



基础知识点
单向数据流（子组件不能修改父组件数据）

组件名首字母大写

可以使用&lt;React.Fragment&gt;&lt;/...</p>
        </a>
      
      
        <a class='next' href='/posts/f9d92613/'>
          <p class='title'>webpack4.0进阶（三）<i class="fas fa-chevron-right" aria-hidden="true"></i></p>
          <p class='content'>手写简单的loader、Plugin、简单的webpack


手写简单的loader目录
myLoader
 ├── loaders
 │   └── myLoader.js
 ├── pac...</p>
        </a>
      
    </div>
  
</article>


  

  <article class="post white-box reveal shadow" id="comments">
    <p ct><i class='fas fa-comments'></i> 评论</p>
    
    <div id="valine_container" class="valine_thread">
  <i class="fas fa-cog fa-spin fa-fw fa-2x"></i>
</div>

  </article>






</div>
<aside class='l_side'>
  
  
    
    



  <section class="widget toc-wrapper shadow desktop mobile" id="toc-div" >
    
  <header>
    
      <i class="fas fa-list fa-fw" aria-hidden="true"></i><span class='name'>本文目录</span>
    
  </header>


    <div class='content'>
        <ol class="toc"><li class="toc-item toc-level-3"><a class="toc-link" href="#什么是TypeScript"><span class="toc-text">什么是TypeScript</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#TypeScript好在哪里"><span class="toc-text">TypeScript好在哪里</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#创建第一个TypeScript文件"><span class="toc-text">创建第一个TypeScript文件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#基础类型"><span class="toc-text">基础类型</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#数组"><span class="toc-text">数组</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#元组tuple"><span class="toc-text">元组tuple</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#枚举"><span class="toc-text">枚举</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#any"><span class="toc-text">any</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#void"><span class="toc-text">void</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#null和undefined"><span class="toc-text">null和undefined</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#never"><span class="toc-text">never</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#结构赋值的写法"><span class="toc-text">结构赋值的写法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#联合类型"><span class="toc-text">联合类型</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#类型断言"><span class="toc-text">类型断言</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#接口interface"><span class="toc-text">接口interface</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#可选属性"><span class="toc-text">可选属性</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#只读属性"><span class="toc-text">只读属性</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#函数类型的接口"><span class="toc-text">函数类型的接口</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#接口的继承"><span class="toc-text">接口的继承</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#类class"><span class="toc-text">类class</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#变量修饰符"><span class="toc-text">变量修饰符</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#静态属性static"><span class="toc-text">静态属性static</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#构造函数"><span class="toc-text">构造函数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#抽象类"><span class="toc-text">抽象类</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#泛型"><span class="toc-text">泛型</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#泛型约束"><span class="toc-text">泛型约束</span></a></li></ol></li></ol>
    </div>
  </section>


  


</aside>



        
        
          <!--此文件用来存放一些不方便取值的变量-->
<!--思路大概是将值藏到重加载的区域内-->

<script>
  window.pdata={}
  pdata.ispage=true;
  pdata.postTitle="TypeScript学习总结（一）";
  pdata.commentPath="";
  pdata.commentPlaceholder="";

  var l_header=document.getElementById("l_header");
  
  l_header.classList.remove("show");
  
</script>

        
      </div>
      
  
  <footer class="footer clearfix">
    <br><br>
    
      
        <div class="aplayer-container">
          


        </div>
      
    
      
        <br>
        <div class="social-wrapper">
          
            
              <a href="mailto:alannum3@qq.com"
                class="social fas fa-envelope flat-btn"
                target="_blank"
                rel="external nofollow noopener noreferrer">
                
              </a>
            
          
            
              <a href="https://github.com/3Alan"
                class="social fab fa-github flat-btn"
                target="_blank"
                rel="external nofollow noopener noreferrer">
                
              </a>
            
          
            
              <a href="tencent://message/?uin=1540703192"
                class="social fab fa-qq flat-btn"
                target="_blank"
                rel="external nofollow noopener noreferrer">
                
              </a>
            
          
            
          
            
          
        </div>
      
    
      
        <div><p>博客内容遵循 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh" target="_blank" rel="noopener">署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议</a></p>
</div>
      
    
      
        <div class='copyright'>
        <p><a href="https://alanwang.site/">Copyright © 2020 Alan</a></p>

        </div>
      
    
  </footer>


      <a id="s-top" class="fas fa-arrow-up fa-fw" href='javascript:void(0)'></a>
    </div>
  </div>
  <div>
    <script>
window.volantis={};
window.volantis.loadcss=document.getElementById("loadcss");
/********************脚本懒加载函数********************************/
function loadScript(src, cb) {
var HEAD = document.getElementsByTagName('head')[0] || document.documentElement;
var script = document.createElement('script');
script.setAttribute('type','text/javascript');
if (cb) script.onload = cb;
script.setAttribute('src', src);
HEAD.appendChild(script);
}
//https://github.com/filamentgroup/loadCSS
var loadCSS = function( href, before, media, attributes ){
	var doc = window.document;
	var ss = doc.createElement( "link" );
	var ref;
	if( before ){
		ref = before;
	}
	else {
		var refs = ( doc.body || doc.getElementsByTagName( "head" )[ 0 ] ).childNodes;
		ref = refs[ refs.length - 1];
	}
	var sheets = doc.styleSheets;
	if( attributes ){
		for( var attributeName in attributes ){
			if( attributes.hasOwnProperty( attributeName ) ){
				ss.setAttribute( attributeName, attributes[attributeName] );
			}
		}
	}
	ss.rel = "stylesheet";
	ss.href = href;
	ss.media = "only x";
	function ready( cb ){
		if( doc.body ){
			return cb();
		}
		setTimeout(function(){
			ready( cb );
		});
	}
	ready( function(){
		ref.parentNode.insertBefore( ss, ( before ? ref : ref.nextSibling ) );
	});
	var onloadcssdefined = function( cb ){
		var resolvedHref = ss.href;
		var i = sheets.length;
		while( i-- ){
			if( sheets[ i ].href === resolvedHref ){
				return cb();
			}
		}
		setTimeout(function() {
			onloadcssdefined( cb );
		});
	};
	function loadCB(){
		if( ss.addEventListener ){
			ss.removeEventListener( "load", loadCB );
		}
		ss.media = media || "all";
	}
	if( ss.addEventListener ){
		ss.addEventListener( "load", loadCB);
	}
	ss.onloadcssdefined = onloadcssdefined;
	onloadcssdefined( loadCB );
	return ss;
};
</script>
<script>
  
  loadCSS("https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.14/css/all.min.css", window.volantis.loadcss);
  
  
  
  
  loadCSS("https://cdn.jsdelivr.net/npm/highlight.js@10.0.3/styles/atom-one-dark.min.css", window.volantis.loadcss);
  
</script>
<!-- required -->

<script src="https://cdn.jsdelivr.net/npm/jquery@3.5/dist/jquery.min.js"></script>

<script>
  function pjax_fancybox() {
    $(".md .gallery").find("img").each(function () { //渲染 fancybox
      var element = document.createElement("a"); // a 标签
      $(element).attr("class", "fancybox");
      $(element).attr("pjax-fancybox", "");  // 过滤 pjax
      $(element).attr("href", $(this).attr("src"));
      if ($(this).attr("data-original")) {
        $(element).attr("href", $(this).attr("data-original"));
      }
      $(element).attr("data-fancybox", "images");
      var caption = "";   // 描述信息
      if ($(this).attr('alt')) {  // 判断当前页面是否存在描述信息
        $(element).attr('data-caption', $(this).attr('alt'));
        caption = $(this).attr('alt');
      }
      var div = document.createElement("div");
      $(div).addClass("fancybox");
      $(this).wrap(div); // 最外层套 div ，其实主要作用还是 class 样式
      var span = document.createElement("span");
      $(span).addClass("image-caption");
      $(span).text(caption); // 加描述
      $(this).after(span);  // 再套一层描述
      $(this).wrap(element);  // 最后套 a 标签
    })
    $(".md .gallery").find("img").fancybox({
      selector: '[data-fancybox="images"]',
      hash: false,
      loop: false,
      closeClick: true,
      helpers: {
        overlay: {closeClick: true}
      },
      buttons: [
        "zoom",
        "close"
      ]
    });
  };
  function SCload_fancybox() {
    if ($(".md .gallery").find("img").length == 0) return;
    loadCSS("https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css", document.getElementById("loadcss"));
    setTimeout(function() {
      loadScript('https://cdn.jsdelivr.net/gh/fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js', pjax_fancybox)
    }, 1);
  };
  $(function () {
    SCload_fancybox();
  });
</script>


<!-- internal -->

  
  
  
    
<script src="https://cdn.jsdelivr.net/npm/jquery-backstretch@2.1.18/jquery.backstretch.min.js"></script>

    <script type="text/javascript">
        var imgs=["https://gitee.com/alannum3/MyImages/raw/master/img/triangles-3321900_1920.png", "https://gitee.com/alannum3/MyImages/raw/master/img/img-8e2c27a1a7510d3b73317e96ec2f4b72.jpg", "https://gitee.com/alannum3/MyImages/raw/master/img/img-2da8b0f6ac052b7b9402dea246a56701.jpg", "https://gitee.com/alannum3/MyImages/raw/master/img/img-389c21fac02e9980506b6f7ff7f130f6.jpg", "https://gitee.com/alannum3/MyImages/raw/master/img/img-b7f5935e94f6deda4fda5e2820c48bef.jpg", "https://gitee.com/alannum3/MyImages/raw/master/img/img-3c991ba94430b0ddf426d9062bbea403.jpg", "https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/002.jpg", "https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/003.jpg", "https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/004.jpg", "https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/005.jpg", "https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/006.jpg", "https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/012.jpg", "https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/016.jpg", "https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/019.jpg", "https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/025.jpg", "https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/033.jpg", "https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/034.jpg", "https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/035.jpg", "https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/038.jpg", "https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/039.jpg", "https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/042.jpg", "https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/046.jpg", "https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/051.jpg", "https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/052.jpg", "https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/054.jpg", "https://cdn.jsdelivr.net/gh/volantis-x/cdn-wallpaper-minimalist/2020/056.jpg"];
        if ('true' == 'true') {
          function shuffle(arr){
            /*From countercurrent-time*/
            var n = arr.length;
            while(n--) {
              var index = Math.floor(Math.random() * n);
              var temp = arr[index];
              arr[index] = arr[n];
              arr[n] = temp;
            }
          }
          shuffle(imgs);
        }
	  function Pjax_backstretch(){
        
          $.backstretch(
            imgs,
          {
            duration: "20000",
            fade: "1500"
          });
        
	  }
	  loadScript("https://cdn.jsdelivr.net/npm/jquery-backstretch@2.1.18/jquery.backstretch.min.js",Pjax_backstretch)
    </script>
  



  
  

  <div id="rightmenu-wrapper">
    <ul class="list-v rightmenu" id="rightmenu-content">
      <li class='option'>
        <a class='vlts-menu opt fix-cursor-default' id='menu-copy-text' onclick="document.execCommand('copy')"><i class='fa fa-copy fa-fw'></i>复制文本</a>
        <hr id='hr-text'>
        <a class='vlts-menu opt fix-cursor-default' id='menu-copy-href'><i class='fa fa-link fa-fw'></i>复制链接</a>
        <a class='vlts-menu opt fix-cursor-default' id='menu-open-href'><i class='fa fa-external-link-square-alt fa-fw'></i>在新标签页打开</a>
        <hr id='hr-href'>
        <a class='vlts-menu opt fix-cursor-default' id='menu-copy-src'><i class='fa fa-image fa-fw'></i>复制图片地址</a>
        <hr id='hr-src'>
      </li>
      
        <li class='navigation'>
          <a class='nav icon-only fix-cursor-default' onclick='history.back()'><i class='fa fa-arrow-left fa-fw'></i></a>
          <a class='nav icon-only fix-cursor-default' onclick='history.forward()'><i class='fa fa-arrow-right fa-fw'></i></a>
          <a class='nav icon-only fix-cursor-default' onclick='window.location.reload()'><i class='fa fa-redo fa-fw'></i></a>
          <a class='nav icon-only fix-cursor-default' href='/'><i class='fa fa-home fa-fw'></i></a>
        </li>
      
      <hr>
      
        
      
        
      
    </ul>
  </div>

  <script>
    window.document.oncontextmenu = function (event) {
      if (event.ctrlKey) return true;
      if (/Android|webOS|BlackBerry/i.test(navigator.userAgent)) return true;
      return popMenu(event);
    };
    document.addEventListener("click", function (event) {
      var mymenu = document.getElementById('rightmenu-wrapper');
      mymenu.style.display = "none";
    });
    function popMenu(event) {
      var mymenu = document.getElementById('rightmenu-wrapper');
      var menuContent = document.getElementById('rightmenu-content');
      var screenWidth = document.documentElement.clientWidth || document.body.clientWidth;
      var screenHeight = document.documentElement.clientHeight || document.body.clientHeight;
      mymenu.style.left = event.clientX + "px"; // 获取鼠标位置
      mymenu.style.top = event.clientY + "px";
      mymenu.style.display = 'block';
      if (event.clientX * 2 > screenWidth) {
        menuContent.classList.add('left');
      } else {
        menuContent.classList.remove('left');
      }
      if (event.clientY * 2 > screenHeight) {
        menuContent.classList.add('top');
      } else {
        menuContent.classList.remove('top');
      }

      let hrText = document.getElementById('hr-text');
      let hrSrc = document.getElementById('hr-src');
      let hrHref = document.getElementById('hr-href');

      // 选中图片
      let copySrc = document.getElementById('menu-copy-src');
      if (copySrc != undefined) {
        if (event.target.currentSrc) {
          copySrc.style.display = 'block';
          copySrc.addEventListener("click", function (e) {
            copyString(event.target.currentSrc);
          },{once: true});
          hrSrc.style.display = 'block';
        } else {
          copySrc.style.display = 'none';
          hrSrc.style.display = 'none';
        }
      }

      // 选中按钮
      // 判断是不是按钮
      let href = '';
      if (event.path) {
        for (i = 0; i < event.path.length; i++) {
          if (event.path[i].href != undefined && event.path[i].href.length > 0) {
            href = event.path[i].href;
          }
        }
      }

      let copyText = document.getElementById('menu-copy-text');
      copyText.style.display = 'none';
      hrText.style.display = 'none';
      if (href.length == 0) {
        // 选中文本
        if (window.getSelection().toString()) {
          if ('true' == 'true') {
            copyText.style.display = 'block';
            hrText.style.display = 'block';
          }
        }
      }

      // 在新标签页打开
      let openHref = document.getElementById('menu-open-href');
      if (openHref != undefined) {
        if (href.length > 0) {
          openHref.style.display = 'block';
          openHref.addEventListener("click", function (e) {
            window.open(href);
          },{once: true});
          hrHref.style.display = 'block';
        } else {
          openHref.style.display = 'none';
          hrHref.style.display = 'none';
        }
      }
      // 复制链接
      let copyHref = document.getElementById('menu-copy-href');
      if (copyHref != undefined) {
        if (href.length > 0) {
          copyHref.style.display = 'block';
          copyHref.addEventListener("click", function (e) {
            copyString(href);
          },{once: true});
        } else {
          copyHref.style.display = 'none';
        }
      }

      // 有音乐播放器
      if ('false' == true && ('home,music'||[]).includes('music')) {
        // 如果有aplayer，初始化一下
      	try {
      		checkAPlayer();
          updateTitle();
      	} catch (error) {
      		console.log(error);
      	}
      }

      return false; // 该行代码确保系统自带的右键菜单不会被调出
    }
    function hideMenu() {
      document.getElementById('rightmenu-wrapper').style.display = 'none';
    }
    function copyString(str) {
      const input = document.createElement('input');
      input.setAttribute('readonly', 'readonly');
      document.body.appendChild(input);
      input.setAttribute('value', str);
      input.select();
      document.execCommand('copy');
      document.body.removeChild(input);
    }
    document.execCommand('click');
  </script>







  <script defer src="https://cdn.jsdelivr.net/npm/vanilla-lazyload@17.1.0/dist/lazyload.min.js"></script>
<script>
  // https://www.npmjs.com/package/vanilla-lazyload
  // Set the options globally
  // to make LazyLoad self-initialize
  window.lazyLoadOptions = {
    elements_selector: ".lazyload",
    threshold: 0
  };
  // Listen to the initialization event
  // and get the instance of LazyLoad
  window.addEventListener(
    "LazyLoad::Initialized",
    function (event) {
      window.lazyLoadInstance = event.detail.instance;
    },
    false
  );
  document.addEventListener('DOMContentLoaded', function () {
    lazyLoadInstance.update();
  });
  document.addEventListener('pjax:complete', function () {
    lazyLoadInstance.update();
  });
</script>




  
  
    <script>
      window.FPConfig = {
        delay: 0,
        ignoreKeywords: [],
        maxRPS: 5,
        hoverDelay: 25
      };
    </script>
    <script defer src="https://cdn.jsdelivr.net/gh/gijo-varghese/flying-pages@2.1.2/flying-pages.min.js"></script>
  




  <script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<script>
    var clipboard = new ClipboardJS('.btn-copy', {
        target: function (trigger) {
            return trigger.nextElementSibling
        }
    });
    function wait(callback, seconds) {
        var timelag = null;
        timelag = window.setTimeout(callback, seconds)
    }
    function pjax_initCopyCode() {
		if($(".highlight .code pre").length+$(".article pre code").length==0)return;
        var copyHtml = '';
        copyHtml += '<button class="btn-copy" data-clipboard-snippet="">';
        copyHtml += '<i class="fas fa-copy"></i><span>COPY</span>';
        copyHtml += '</button>';
        $(".highlight .code pre").before(copyHtml);
        $(".article pre code").before(copyHtml);
        clipboard.off('success').on('success', function (e) {
            let $btn = $(e.trigger);
            $btn.addClass('copied');
            let $icon = $($btn.find('i'));
            $icon.removeClass('fa-copy');
            $icon.addClass('fa-check-circle');
            let $span = $($btn.find('span'));
            $span[0].innerText = 'COPIED';
            wait(function () {
                $icon.removeClass('fa-check-circle');
                $icon.addClass('fa-copy');
                $span[0].innerText = 'COPY'
            }, 2000)
        });
        clipboard.off('error').on('error', function (e) {
            e.clearSelection();
            let $btn = $(e.trigger);
            $btn.addClass('copy-failed');
            let $icon = $($btn.find('i'));
            $icon.removeClass('fa-copy');
            $icon.addClass('fa-times-circle');
            let $span = $($btn.find('span'));
            $span[0].innerText = 'COPY FAILED';
            wait(function () {
                $icon.removeClass('fa-times-circle');
                $icon.addClass('fa-copy');
                $span[0].innerText = 'COPY'
            }, 2000)
        })
    }
    $(function () {
        pjax_initCopyCode()
    });
</script>








  
  
<script src="https://cdn.jsdelivr.net/npm/valine@1.4/dist/Valine.min.js"></script>


<script>
  var GUEST_INFO = ['nick', 'mail', 'link'];
  var meta = 'nick,mail,link'.split(',').filter(function (item) {
    return GUEST_INFO.indexOf(item) > -1
  });
  var REQUIRED_FIELDS = ['nick', 'mail', 'link'];
  var requiredFields = 'nick,mail'.split(',').filter(function (item) {
    return REQUIRED_FIELDS.indexOf(item) > -1
  });

  function emoji(path, idx, ext) {
    return path + "/" + path + "-" + idx + "." + ext;
  }

  var emojiMaps = {};
  for (var i = 1; i <= 54; i++) {
    emojiMaps['tieba-' + i] = emoji('tieba', i, 'png');
  }
  for (var i = 1; i <= 101; i++) {
    emojiMaps['qq-' + i] = emoji('qq', i, 'gif');
  }
  for (var i = 1; i <= 116; i++) {
    emojiMaps['aru-' + i] = emoji('aru', i, 'gif');
  }
  for (var i = 1; i <= 125; i++) {
    emojiMaps['twemoji-' + i] = emoji('twemoji', i, 'png');
  }
  for (var i = 1; i <= 4; i++) {
    emojiMaps['weibo-' + i] = emoji('weibo', i, 'png');
  }

  function pjax_valine() {
    if(!document.querySelectorAll("#valine_container")[0])return;

    let pagePlaceholder = pdata.commentPlaceholder || "快来评论吧~";

    let path = pdata.commentPath;
    if (path.length == 0) {
      let defaultPath = '';
      path = defaultPath || decodeURI(window.location.pathname);
    }

    var valine = new Valine();
    valine.init({
      el: '#valine_container',
      meta: meta,
      placeholder: pagePlaceholder,
      path: path,
      appId: "aowgxqHE7wB4I8HLWqC4c4Ut-MdYXbMMI",
      appKey: "37wkY4T3cM7nV2UWV7EIEHPy",
      pageSize: '10',
      avatar: 'robohash',
      lang: 'zh-cn',
      visitor: 'true',
      highlight: 'true',
      mathJax: 'false',
      enableQQ: 'true',
      recordIP: 'false',
      requiredFields: requiredFields,
      emojiCDN: 'https://cdn.jsdelivr.net/gh/volantis-x/cdn-emoji/valine/',
      emojiMaps: emojiMaps
    })
  }

  $(function () {
    pjax_valine();
  });
</script>




  <script defer src="https://cdn.jsdelivr.net/gh/volantis-x/cdn-busuanzi@2.3/js/busuanzi.pure.mini.js" data-pjax></script>


  
<script src="https://cdn.jsdelivr.net/npm/hexo-theme-volantis@4.1.5/source/js/app.min.js"></script>




  
  
<script src="https://cdn.jsdelivr.net/npm/hexo-theme-volantis@4.1.5/source/js/search.min.js"></script>

  


<!-- optional -->

  <script>
const SearchServiceimagePath="https://cdn.jsdelivr.net/gh/volantis-x/cdn-volantis@master/img/";
const ROOT =  ("/" || "/").endsWith('/') ? ("/" || "/") : ("//" || "/" );
function listenSearch(){
  
    customSearch = new HexoSearch({
      imagePath: SearchServiceimagePath
    });
  
}
document.addEventListener("DOMContentLoaded", listenSearch);

</script>







  
<script src="https://cdn.jsdelivr.net/gh/volantis-x/cdn-volantis@2/js/comment_typing.js"></script>




  
    
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@9.18.1/build/highlight.min.js"></script>

    <script>hljs.initHighlightingOnLoad();</script>
  



  <script defer>

  const LCCounter = {
    app_id: 'aowgxqHE7wB4I8HLWqC4c4Ut-MdYXbMMI',
    app_key: '37wkY4T3cM7nV2UWV7EIEHPy',
    custom_api_server: '',

    // 查询存储的记录
    getRecord(Counter, url, title) {
      return new Promise(function (resolve, reject) {
        Counter('get', '/classes/Counter?where=' + encodeURIComponent(JSON.stringify({url})))
          .then(resp => resp.json())
          .then(({results, code, error}) => {
            if (code === 401) {
              throw error;
            }
            if (results && results.length > 0) {
              var record = results[0];
              resolve(record);
            } else {
              Counter('post', '/classes/Counter', {url, title: title, times: 0})
                .then(resp => resp.json())
                .then((record, error) => {
                  if (error) {
                    throw error;
                  }
                  resolve(record);
                }).catch(error => {
                console.error('Failed to create', error);
                reject(error);
              });
            }
          }).catch((error) => {
          console.error('LeanCloud Counter Error:', error);
          reject(error);
        });
      })
    },

    // 发起自增请求
    increment(Counter, incrArr) {
      return new Promise(function (resolve, reject) {
        Counter('post', '/batch', {
          "requests": incrArr
        }).then((res) => {
          res = res.json();
          if (res.error) {
            throw res.error;
          }
          resolve(res);
        }).catch((error) => {
          console.error('Failed to save visitor count', error);
          reject(error);
        });
      });
    },

    // 构建自增请求体
    buildIncrement(objectId) {
      return {
        "method": "PUT",
        "path": `/1.1/classes/Counter/${ objectId }`,
        "body": {
          "times": {
            '__op': 'Increment',
            'amount': 1
          }
        }
      }
    },

    // 校验是否为有效的 UV
    validUV() {
      var key = 'LeanCloudUVTimestamp';
      var flag = localStorage.getItem(key);
      if (flag) {
        // 距离标记小于 24 小时则不计为 UV
        if (new Date().getTime() - parseInt(flag) <= 86400000) {
          return false;
        }
      }
      localStorage.setItem(key, new Date().getTime().toString());
      return true;
    },

    addCount(Counter) {
      var enableIncr = '' === 'true' && window.location.hostname !== 'localhost';
      enableIncr = true;
      var getterArr = [];
      var incrArr = [];
      // 请求 PV 并自增
      var pvCtn = document.querySelector('#lc-sv');
      if (pvCtn || enableIncr) {
        var pvGetter = this.getRecord(Counter, 'https://alanwang.site' + '/#lc-sv', 'Visits').then((record) => {
          incrArr.push(this.buildIncrement(record.objectId))
          var eles = document.querySelectorAll('#lc-sv #number');
          if (eles.length > 0) {
            eles.forEach((el,index,array)=>{
              el.innerText = record.times + 1;
              if (pvCtn) {
                pvCtn.style.display = 'inline';
              }
            })
          }
        });
        getterArr.push(pvGetter);
      }

      // 请求 UV 并自增
      var uvCtn = document.querySelector('#lc-uv');
      if (uvCtn || enableIncr) {
        var uvGetter = this.getRecord(Counter, 'https://alanwang.site' + '/#lc-uv', 'Visitors').then((record) => {
          var vuv = this.validUV();
          vuv && incrArr.push(this.buildIncrement(record.objectId))
          var eles = document.querySelectorAll('#lc-uv #number');
          if (eles.length > 0) {
            eles.forEach((el,index,array)=>{
              el.innerText = record.times + (vuv ? 1 : 0);
              if (uvCtn) {
                uvCtn.style.display = 'inline';
              }
            })
          }
        });
        getterArr.push(uvGetter);
      }

      // 请求文章的浏览数，如果是当前页面就自增
      var allPV = document.querySelectorAll('#lc-pv');
      if (allPV.length > 0 || enableIncr) {
        for (i = 0; i < allPV.length; i++) {
          let pv = allPV[i];
          let title = pv.getAttribute('data-title');
          var url = 'https://alanwang.site' + pv.getAttribute('data-path');
          if (url) {
            var viewGetter = this.getRecord(Counter, url, title).then((record) => {
              // 是当前页面就自增
              let curPath = window.location.pathname;
              if (curPath.includes('index.html')) {
                curPath = curPath.substring(0, curPath.lastIndexOf('index.html'));
              }
              if (pv.getAttribute('data-path') == curPath) {
                incrArr.push(this.buildIncrement(record.objectId));
              }
              if (pv) {
                var ele = pv.querySelector('#lc-pv #number');
                if (ele) {
                  if (pv.getAttribute('data-path') == curPath) {
                    ele.innerText = (record.times || 0) + 1;
                  } else {
                    ele.innerText = record.times || 0;
                  }
                  pv.style.display = 'inline';
                }
              }
            });
            getterArr.push(viewGetter);
          }
        }
      }

      // 如果启动计数自增，批量发起自增请求
      if (enableIncr) {
        Promise.all(getterArr).then(() => {
          incrArr.length > 0 && this.increment(Counter, incrArr);
        })
      }

    },


    fetchData(api_server) {
      var Counter = (method, url, data) => {
        return fetch(`${ api_server }/1.1${ url }`, {
          method,
          headers: {
            'X-LC-Id': this.app_id,
            'X-LC-Key': this.app_key,
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(data)
        });
      };
      this.addCount(Counter);
    },

    refreshCounter() {
      var api_server = this.app_id.slice(-9) !== '-MdYXbMMI' ? this.custom_api_server : `https://${ this.app_id.slice(0, 8).toLowerCase() }.api.lncldglobal.com`;
      if (api_server) {
        this.fetchData(api_server);
      } else {
        fetch('https://app-router.leancloud.cn/2/route?appId=' + this.app_id)
          .then(resp => resp.json())
          .then(({api_server}) => {
            this.fetchData('https://' + api_server);
          });
      }
    }

  };

  LCCounter.refreshCounter();

  document.addEventListener('pjax:complete', function () {
    LCCounter.refreshCounter();
  });
</script>




  <script>
const rootElement = document.documentElement;
const darkModeStorageKey = "user-color-scheme";
const rootElementDarkModeAttributeName = "data-user-color-scheme";

const setLS = (k, v) => {
  try {
    localStorage.setItem(k, v);
  } catch (e) {
    console.log(e.message);
  }
};

const removeLS = (k) => {
  try {
    localStorage.removeItem(k);
  } catch (e) {
    console.log(e.message);
  }
};

const getLS = (k) => {
  try {
    return localStorage.getItem(k);
  } catch (e) {
    console.log(e.message);
    return null;
  }
};

const getModeFromCSSMediaQuery = () => {
  return window.matchMedia("(prefers-color-scheme: dark)").matches
    ? "dark"
    : "light";
};

const resetRootDarkModeAttributeAndLS = () => {
  rootElement.removeAttribute(rootElementDarkModeAttributeName);
  removeLS(darkModeStorageKey);
};

const validColorModeKeys = {
  dark: true,
  light: true,
};

const applyCustomDarkModeSettings = (mode) => {
  const currentSetting = mode || getLS(darkModeStorageKey);

  if (currentSetting === getModeFromCSSMediaQuery()) {
    resetRootDarkModeAttributeAndLS();
  } else if (validColorModeKeys[currentSetting]) {
    rootElement.setAttribute(rootElementDarkModeAttributeName, currentSetting);
  } else {
    resetRootDarkModeAttributeAndLS();
  }
};

const invertDarkModeObj = {
  dark: "light",
  light: "dark",
};

/**
 * get target mode
 */
const toggleCustomDarkMode = () => {
  let currentSetting = getLS(darkModeStorageKey);

  if (validColorModeKeys[currentSetting]) {
    currentSetting = invertDarkModeObj[currentSetting];
  } else if (currentSetting === null) {
    currentSetting = invertDarkModeObj[getModeFromCSSMediaQuery()];
  } else {
    return;
  }
  setLS(darkModeStorageKey, currentSetting);
  return currentSetting;
};

/**
 * bind click event for toggle button
 */
function bindToggleButton() {
	var btn=$("#wrapper .toggle-mode-btn");
    btn.on('click',(e) => {
      const mode = toggleCustomDarkMode();
      applyCustomDarkModeSettings(mode);
    });
}

applyCustomDarkModeSettings();
document.addEventListener("DOMContentLoaded", bindToggleButton);
document.addEventListener("pjax:success", bindToggleButton);

</script>





<!-- baidu Analytics -->
<script>
var _hmt = _hmt || [];
(function() {
  setTimeout(function() {
	var hm = document.createElement("script");
	hm.src = "https://hm.baidu.com/hm.js?ff1856f91533fcea9c8c2fe5a1b06fe7";
	hm.defer=true;
	var s = document.getElementsByTagName("script")[0];
	s.parentNode.insertBefore(hm, s);
  }, 5000);
})();
</script>


<script>
function listennSidebarTOC() {
  const navItems = document.querySelectorAll(".toc li");
  if (!navItems.length) return;
  const sections = [...navItems].map((element) => {
    const link = element.querySelector(".toc-link");
    const target = document.getElementById(
      decodeURI(link.getAttribute("href")).replace("#", "")
    );
    link.addEventListener("click", (event) => {
      event.preventDefault();
      window.scrollTo({
		top: target.offsetTop + 100,
		
		behavior: "smooth"
		
	  });
    });
    return target;
  });

  function activateNavByIndex(target) {
    if (target.classList.contains("active-current")) return;

    document.querySelectorAll(".toc .active").forEach((element) => {
      element.classList.remove("active", "active-current");
    });
    target.classList.add("active", "active-current");
    let parent = target.parentNode;
    while (!parent.matches(".toc")) {
      if (parent.matches("li")) parent.classList.add("active");
      parent = parent.parentNode;
    }
  }

  function findIndex(entries) {
    let index = 0;
    let entry = entries[index];
    if (entry.boundingClientRect.top > 0) {
      index = sections.indexOf(entry.target);
      return index === 0 ? 0 : index - 1;
    }
    for (; index < entries.length; index++) {
      if (entries[index].boundingClientRect.top <= 0) {
        entry = entries[index];
      } else {
        return sections.indexOf(entry.target);
      }
    }
    return sections.indexOf(entry.target);
  }

  function createIntersectionObserver(marginTop) {
    marginTop = Math.floor(marginTop + 10000);
    let intersectionObserver = new IntersectionObserver(
      (entries, observe) => {
        let scrollHeight = document.documentElement.scrollHeight + 100;
        if (scrollHeight > marginTop) {
          observe.disconnect();
          createIntersectionObserver(scrollHeight);
          return;
        }
        let index = findIndex(entries);
        activateNavByIndex(navItems[index]);
      },
      {
        rootMargin: marginTop + "px 0px -100% 0px",
        threshold: 0,
      }
    );
    sections.forEach((element) => {
      element && intersectionObserver.observe(element);
    });
  }
  createIntersectionObserver(document.documentElement.scrollHeight);
}

document.addEventListener("DOMContentLoaded", listennSidebarTOC);
document.addEventListener("pjax:success", listennSidebarTOC);
</script>

<!-- more -->




    
      


<script src="https://cdn.jsdelivr.net/npm/pjax@0.2.8/pjax.min.js"></script>


<script>
    var pjax;
    document.addEventListener('DOMContentLoaded', function () {
      pjax = new Pjax({
        elements: 'a[href]:not([href^="#"]):not([href="javascript:void(0)"]):not([pjax-fancybox])',
        selectors: [
          "title",
          "#l_cover",
          "#pjax-container",
          "#pjax-header-nav-list"
        ],
        cacheBust: false,   // url 地址追加时间戳，用以避免浏览器缓存
        timeout: 5000
      });
    });

    document.addEventListener('pjax:send', function (e) {
      //window.stop(); // 相当于点击了浏览器的停止按钮

      try {
        var currentUrl = window.location.pathname;
        var targetUrl = e.triggerElement.href;
        var banUrl = [""];
        if (banUrl[0] != "") {
          banUrl.forEach(item => {
            if(currentUrl.indexOf(item) != -1 || targetUrl.indexOf(item) != -1) {
              window.location.href = targetUrl;
            }
          });
        }
      } catch (error) {}

      window.subData = null; // 移除标题（用于一二级导航栏切换处）
      if (typeof $.fancybox != "undefined") {
        $.fancybox.close();    // 关闭弹窗
      }
      volantis.$switcher.removeClass('active'); // 关闭移动端激活的搜索框
      volantis.$header.removeClass('z_search-open'); // 关闭移动端激活的搜索框
      volantis.$wrapper.removeClass('sub'); // 跳转页面时关闭二级导航

      // 解绑事件 避免重复监听
      volantis.$topBtn.unbind('click');
      $('.menu a').unbind('click');
      $(window).unbind('resize');
      $(window).unbind('scroll');
      $(document).unbind('scroll');
      $(document).unbind('click');
      $('body').unbind('click');
	  
    });

    document.addEventListener('pjax:complete', function () {
      // 关于百度统计对 SPA 页面的处理：
      // 方案一：百度统计>管理>单页应用设置中，打开开启按钮即可对SPA进行统计。 https://tongji.baidu.com/web/help/article?id=324
      // 方案二：取消注释下列代码。 https://tongji.baidu.com/web/help/article?id=235
      // 
      // _hmt.push(['_trackPageview', document.location.pathname]);
      // 

      // 关于谷歌统计对 SPA 页面的处理：
      // 当应用以动态方式加载内容并更新地址栏中的网址时，也应该更新通过 gtag.js 存储的网页网址。
      // https://developers.google.cn/analytics/devguides/collection/gtagjs/single-page-applications?hl=zh-cn
      

      $('.nav-main').find('.list-v').not('.menu-phone').removeAttr("style",""); // 移除小尾巴的移除
      $('.menu-phone.list-v').removeAttr("style",""); // 移除小尾巴的移除
      $('script[data-pjax], .pjax-reload script').each(function () {
        $(this).parent().append($(this).remove());
      });
      try{
          if (typeof $.fancybox == "undefined") {
            SCload_fancybox();
          } else {
            pjax_fancybox();
          }
        
		  Pjax_backstretch()
        
        
        document.querySelectorAll('pre code').forEach((block) => {
          hljs.highlightBlock(block);
        });
        
        
        
        
          pjax_initCopyCode();
        
        
          pjax_valine();
        
        
        
        
      } catch (e) {
        console.log(e);
      }
	  
    });

    document.addEventListener('pjax:error', function (e) {
	  
      window.location.href = e.triggerElement.href;
    });
</script>

    
  </div>
<script>
            window.imageLazyLoadSetting = {
                isSPA: false,
                processImages: null,
            };
        </script><script>window.addEventListener("load",function(){var t=/\.(gif|jpg|jpeg|tiff|png)$/i,r=/^data:image\/[a-z]+;base64,/;Array.prototype.slice.call(document.querySelectorAll("img[data-original]")).forEach(function(a){var e=a.parentNode;"A"===e.tagName&&(e.href.match(t)||e.href.match(r))&&(e.href=a.dataset.original)})});</script><script>!function(n){n.imageLazyLoadSetting.processImages=i;var e=n.imageLazyLoadSetting.isSPA,r=Array.prototype.slice.call(document.querySelectorAll("img[data-original]"));function i(){e&&(r=Array.prototype.slice.call(document.querySelectorAll("img[data-original]")));for(var t,a=0;a<r.length;a++)0<=(t=(t=r[a]).getBoundingClientRect()).bottom&&0<=t.left&&t.top<=(n.innerHeight||document.documentElement.clientHeight)&&function(){var t,e,n,i,o=r[a];t=o,e=function(){r=r.filter(function(t){return o!==t})},n=new Image,i=t.getAttribute("data-original"),n.onload=function(){t.src=i,e&&e()},n.src=i}()}i(),n.addEventListener("scroll",function(){var t,e;t=i,e=n,clearTimeout(t.tId),t.tId=setTimeout(function(){t.call(e)},500)})}(this);</script></body>
</html>
